//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "cprocess.h"
#include "cthread.h"
#include "cevent.h"
#include "cmutex.h"
#include "cmodule.h"
#include "objenum.h"
#include "pseudo.h"
#include "pcentral.h"
#include "helper.h"
#include "sysevent.h"
#include "servicekit.h"
#include <aura.h>
#include <elacs.h>

#define E_PROCESS_ABORTED 0x000004

#define Lock(hCritical)   do {AuraCriticalSection_Enter(hCritical); }while(0)
#define Unlock(hCritical) do {AuraCriticalSection_Leave(hCritical); }while(0)

#define LOCK_MODULE_LIST   Lock(m_hModuleListLock)
#define UNLOCK_MODULE_LIST Unlock(m_hModuleListLock)
#define LOCK_THREAD_LIST   Lock(m_hThreadListLock)
#define UNLOCK_THREAD_LIST Unlock(m_hThreadListLock)

CProcess::CProcess()
    : m_processId(0),
      m_hProcess(NULL),
      m_pMainThread(NULL),
      m_threadListState(0),
      m_hThreadListLock(NULL),
      m_moduleListState(0),
      m_hModuleListLock(NULL),
      m_exitCode(-1),
      m_threadPoolCapacity(3),  // default value for thread pool capacity.
      m_hTlsLock(NULL)
{
    DLinkNode::Initialize();
    m_threadList.Initialize();
    m_moduleList.Initialize();

    m_processId = AuraProcess_GetCurrentId();

    memset(m_tlsSlotType, ThreadLocalSlotType_Free, TLS_TOTAL_SLOTS);
    m_tlsSlotType[TL_SEQUENCED_SLOT] = ThreadLocalSlotType_Value;
    m_tlsSlotType[TL_QUIT_SLOT]      = ThreadLocalSlotType_Obj;
    m_tlsSlotType[TL_DOMAIN_SLOT] = ThreadLocalSlotType_Value;
    m_tlsSlotType[TL_CALLBACK_SLOT] = ThreadLocalSlotType_Obj;
    m_tlsSlotType[TL_HELPER_INFO_SLOT] = ThreadLocalSlotType_Value;
    m_tlsSlotType[TL_APPLET_SLOT] = ThreadLocalSlotType_Obj;
    m_tlsSlotType[TL_ORG_CALLBACK_SLOT] = ThreadLocalSlotType_Obj;
    m_tlsSlotType[TL_APPLET_DIR_SLOT] = ThreadLocalSlotType_Value;
}

CProcess::~CProcess()
{
    CModule *pModule = NULL;
    while (!m_moduleList.IsEmpty()) {
        pModule = (CModule *)m_moduleList.Next();
        pModule->Detach();
        delete pModule;
        //pModule->Release();
        pModule = NULL;
    }

    if (NULL != m_hProcess) {
        AuraProcess_Destroy(m_hProcess);
        m_hProcess = NULL;
    }
    if (NULL != m_hModuleListLock) {
        AuraCriticalSection_Destroy(m_hModuleListLock);
        m_hModuleListLock = NULL;
    }
    if (NULL != m_hThreadListLock) {
        AuraCriticalSection_Destroy(m_hThreadListLock);
        m_hThreadListLock = NULL;
    }
    if (NULL != m_hTlsLock) {
        AuraCriticalSection_Destroy(m_hTlsLock);
        m_hTlsLock = NULL;
    }
    if (NULL != m_pMainThread) {
        m_pMainThread->Release();
        m_pMainThread = NULL;
    }
}

ECode CProcess::Initialize()
{
    ECode ec = NOERROR;

    ec = AuraProcess_Open(m_processId, &m_hProcess);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = AuraCriticalSection_Create(&m_hThreadListLock);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = AuraCriticalSection_Create(&m_hModuleListLock);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = AuraCriticalSection_Create(&m_hTlsLock);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CThread::S_Create((IProcess *)this, &m_pMainThread);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    m_threadList.InsertLast((CThread *)m_pMainThread);

    ec = this->ModulesInitialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    return ec;

ErrorExit:
    if (NULL != m_pMainThread) {
        m_pMainThread->Release();
        m_pMainThread = NULL;
    }
    if (NULL != m_hTlsLock) {
        AuraCriticalSection_Destroy(m_hTlsLock);
        m_hTlsLock = NULL;
    }
    if (NULL != m_hModuleListLock) {
        AuraCriticalSection_Destroy(m_hModuleListLock);
        m_hModuleListLock = NULL;
    }
    if (NULL != m_hThreadListLock) {
        AuraCriticalSection_Destroy(m_hThreadListLock);
        m_hThreadListLock = NULL;
    }
    if (NULL != m_hProcess) {
        AuraProcess_Destroy(m_hProcess);
        m_hProcess = NULL;
    }
    return ec;
}

ECode CProcess::TrySetStartInfo()
{
    ECode ec = NOERROR;

    ec = AuraProcess_GetStartInfo(m_name.GetPayload(),
                                m_args.GetPayload());
    if (FAILED(ec)) {
        goto E_FAIL_EXIT;
    }

    ec = CPseudoCentral::Process_Open(m_name, m_args, m_processId);
    if (FAILED(ec) && (ec != E_ALREADY_EXIST)) {
        goto E_FAIL_EXIT;
    }
    return NOERROR;

E_FAIL_EXIT:
    return ec;
}

ECode CProcess::ModulesInitialize()
{
    Aura_Handle hModuleSnapshot = NULL;
    Boolean bExistedMore = FALSE;
    Aura_Handle hModule = NULL;
    ECode ec = NOERROR;

    ec = AuraModule_CreateModuleSnapshot(m_processId, &hModuleSnapshot);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = AuraModule_GetModuleNode(hModuleSnapshot,
                              AURA_TRUE,
                              (Aura_Bool *)&bExistedMore,
                              &hModule);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    while (bExistedMore) {
        CModule * pModule = new CModule(m_processId,
                                      (IProcess *)this,
                                      m_hModuleListLock);
        if (NULL == pModule) {
            ec = E_OUT_OF_MEMORY;
            goto ErrorExit;
        }
        ec = pModule->Initialize(hModule);
        if (FAILED(ec)) {
            goto ErrorExit;
        }
        pModule->AddRef();
        m_moduleList.InsertLast(pModule);

        ec = AuraModule_GetModuleNode(hModuleSnapshot,
                                    AURA_FALSE,
                                    (Aura_Bool *)&bExistedMore,
                                    &hModule);
        if (FAILED(ec)) {
            goto ErrorExit;
        }
    }

    AuraModule_CloseModuleSnapshot(hModuleSnapshot);
    return NOERROR;

ErrorExit:
    if (NULL != hModuleSnapshot) {
        AuraModule_CloseModuleSnapshot(hModuleSnapshot);
        hModuleSnapshot = NULL;
    }
    // TODO : need to release modules in the module list.
    return ec;
}

PInterface CProcess::Probe(
    /* [in]  */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)(IProcess *)this;
    }
    else if (riid == EIID_IProcess) {
        return (IProcess *)this;
    }
    else if (riid == EIID_IMemoryTrace) {
        return (IMemoryTrace *)(_CMemoryTrace *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CProcess;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_IProcess;
    }

    return NULL;
}

UInt32 CProcess::AddRef()
{
    Int32 nRef = m_Refs.Increment();
    return (UInt32)nRef;
}

UInt32 CProcess::Release()
{
    Int32 nRef;

    nRef = m_Refs.Decrement();
    if (0 == nRef) {
        delete this;
    }
    return (UInt32)nRef;
}

ECode CProcess::Aggregate(
    /* [in] */ AggregateType type,
    /* [in] */ PInterface pObject)
{
    return E_NOT_IMPLEMENTED;
}

ECode CProcess::GetDomain(
    /* [out] */ PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CProcess::Start(
    /* [in] */ WString name,
    /* [in] */ WString args)
{
    // Notice: The process has already started and running
    // now.
    return E_PROCESS_ALREADY_STARTED;
}

ECode CProcess::Kill()
{
    this->DoAtExit(3);
    assert(0);

    return NOERROR;
}

ECode CProcess::WaitForExit(
    /* [in]  */ Millisecond32 timeout,
    /* [out] */ WaitResult *pResult)
{
    // NOTICE1: It's invalid and necessary for process to wait
    // for another to exit from (or finish) execution routine,
    // but invalid to wait for iteslf.

    // NOTICE2: This method would never be called by proxy.
    return E_INVALID_OPERATION;
}

ECode CProcess::IsAlive(
    /* [out] */ Boolean *pAlive)
{
    *pAlive = TRUE;
    return NOERROR;
}

ECode CProcess::SetPriorityRank(
    /* [in]  */ ThreadPriorityRank priorityRank)
{
    switch (priorityRank) {
        case ThreadPriorityRank_Normal:
        case ThreadPriorityRank_SoftRealTime:
            break;
        case ThreadPriorityRank_HardRealTime:
            return E_NOT_IMPLEMENTED;
        default:
            return E_INVALID_ARGUMENT;
    }

    return AuraProcess_SetPriorityRank(m_hProcess, priorityRank);
}

ECode CProcess::GetPriorityRank(
    /* [out] */ ThreadPriorityRank * pPriorityRank)
{
    if (NULL == pPriorityRank) {
        return E_INVALID_ARGUMENT;
    }
    return AuraProcess_GetPriorityRank(m_hProcess,
                        (Aura_ThreadPriorityRank *)pPriorityRank);
}

ECode CProcess::SetThreadPoolCapacity(
    /* [in]  */ Int32 capacity)
{
    m_threadPoolCapacity = capacity;
    // BUG : TODO -- thread pool mechanism.
    return NOERROR;
}

ECode CProcess::GetThreadPoolState(
    /* [out] */ Int32 * pCapacity,
    /* [out] */ Int32 * pThreads)
{
    if ((NULL == pCapacity) && (NULL == pThreads)) {
        return E_INVALID_ARGUMENT;
    }

    if (NULL != pCapacity) {
        *pCapacity = m_threadPoolCapacity;
    }
    if (NULL != pThreads) {
        *pThreads = 0; // TODO.
    }
    return NOERROR;
}

ECode CProcess::GetAllThreads(
    /* [out] */ IObjectEnumerator **ppThreads)
{
    IObjectEnumerator *pEnumerator = NULL;

    if (NULL == ppThreads) {
        return E_INVALID_ARGUMENT;
    }

    pEnumerator = new CObjectEnumerator(&m_threadList,
                                    m_hThreadListLock,
                                   &m_threadListState,
                                   (IInterface *)this);
    if (NULL == pEnumerator) {
        return E_OUT_OF_MEMORY;
    }
    *ppThreads = pEnumerator;
    (*ppThreads)->AddRef();

    return NOERROR;
}

ECode CProcess::GetAllModules(
    /* [out] */ IObjectEnumerator **ppModules)
{
    IObjectEnumerator *pEnumerator = NULL;

    if (NULL == ppModules) {
        return E_INVALID_ARGUMENT;
    }
    // TODO: Add the originally loaded modules to the m_moduleList.
    pEnumerator = new CObjectEnumerator(&m_moduleList,
                                    m_hModuleListLock,
                                    &m_moduleListState,
                                    (IInterface *)this);
    if (NULL == pEnumerator) {
        return E_OUT_OF_MEMORY;
    }
    *ppModules = pEnumerator;
    (*ppModules)->AddRef();

    return NOERROR;
}

ECode CProcess::GetModuleByName(
    /* [in]  */ WString name,
    /* [out] */ IModule ** ppModule)
{
    CModule * pModule = NULL;

    if (name.IsNullOrEmpty()
     || (NULL == ppModule)) {
        return E_INVALID_ARGUMENT;
    }

    LOCK_MODULE_LIST;
    ForEachDLinkNode(CModule*, pModule, &m_moduleList) {
        if (pModule->Compare(name)) {
            *ppModule = static_cast<IModule *>(pModule);
            (*ppModule)->AddRef();
            Unlock(m_hModuleListLock);
            return NOERROR;
        }
    }
    UNLOCK_MODULE_LIST;

    return E_DOES_NOT_EXIST;
}

ECode CProcess::GetModuleByAddress(
    /* [in]  */ Address address,
    /* [out] */ IModule * * ppModule)
{
    CModule * pModule = NULL;

    if (NULL == ppModule) {
        return E_INVALID_ARGUMENT;
    }

    LOCK_MODULE_LIST;
    ForEachDLinkNode(CModule*, pModule, &m_moduleList) {
        if (pModule->Compare(address)) {
            *ppModule = static_cast<IModule*>(pModule);
            (*ppModule)->AddRef();
            Unlock(m_hModuleListLock);
            return NOERROR;
        }
    }
    UNLOCK_MODULE_LIST;

    return E_DOES_NOT_EXIST;
}

ECode CProcess::GetId(
    /* [out] */ ProcessId * pPid)
{
    if (NULL == pPid) {
        return E_INVALID_ARGUMENT;
    }

    *pPid = m_processId;
    return NOERROR;
}

ECode CProcess::GetStartInfo(
        /* [out] */ WStringBuf * pName,
        /* [out] */ WStringBuf * pArgs)
{
    if ((pName == NULL || !pName->GetCapacity()) &&
        (pArgs == NULL || !pArgs->GetCapacity())) {
        return E_INVALID_ARGUMENT;
    }

    if ((NULL != pName) && (pName->GetCapacity())) {
        pName->Copy(m_name);
    }
    if ((NULL != pArgs) && (pArgs->GetCapacity())) {
        pArgs->Copy(m_args);
    }

    return NOERROR;
}

ECode CProcess::GetExitCode(
    /* [out] */ ExitCode * pExitCode)
{
    if (NULL == pExitCode) {
        return E_INVALID_ARGUMENT;
    }

    *pExitCode = E_PROCESS_STILL_ACTIVE;

    return E_PROCESS_NOT_EXITED;
}

ECode CProcess::GetStartTime(
    /* [out] */ SystemTime * pTime)
{
    if (NULL == pTime) {
        return E_INVALID_ARGUMENT;
    }

    return CPseudoCentral::Process_GetStartTime(m_processId, pTime);
}

ECode CProcess::GetExitTime(
    /* [out] */ SystemTime * pTime)
{
    if (NULL == pTime) {
        return E_INVALID_ARGUMENT;
    }

    return E_PROCESS_NOT_EXITED;
}

ECode CProcess::GetProcessorTimes(
    /* [out] */ Millisecond32 * pUserTime,
    /* [out] */ Millisecond32 * pKernelTime)
{
    if ((NULL == pUserTime)
     && (NULL == pKernelTime)) {
        return E_INVALID_ARGUMENT;
    }

    return AuraProcess_GetProcessorTimes(m_hProcess,
                          (Aura_Millisecond32 *)pUserTime,
                          (Aura_Millisecond32 *)pKernelTime);
}

ECode CProcess::GetMemorySizes(
    /* [out] */ MemorySize * pPrivateVirtualMemorySize,
    /* [out] */ MemorySize * pSharedVirtualMemorySize,
    /* [out] */ MemorySize * pPrivatePhysicalMemorySize,
    /* [out] */ MemorySize * pSharedPhysicalMemorySize)
{
    if ((NULL == pPrivateVirtualMemorySize)
        && (NULL == pSharedVirtualMemorySize)
        && (NULL == pPrivatePhysicalMemorySize)
        && (NULL == pSharedPhysicalMemorySize)) {
        return E_INVALID_ARGUMENT;
    }

    return AuraProcess_GetMemoryInformation(m_hProcess,
                         (Aura_Int32 *)pPrivateVirtualMemorySize,
                         (Aura_Int32 *)pSharedVirtualMemorySize,
                         (Aura_Int32 *)pPrivatePhysicalMemorySize,
                         (Aura_Int32 *)pSharedPhysicalMemorySize);
}

// ---------for Thread Local Slot -----------------
ECode CProcess::AcquireThreadLocalSlot(
    /* [in]  */ ThreadLocalSlotType type,
    /* [out] */ Int32 *pSlotIndex)
{
    Int32 index = 0;

    switch(type) {
    case ThreadLocalSlotType_Value:
    case ThreadLocalSlotType_Mem:
    case ThreadLocalSlotType_Obj:
        break;
    default:
        return E_INVALID_ARGUMENT;
    }
    if (NULL == pSlotIndex) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hTlsLock);
    for (; index < TLS_MINIMUM_AVAILABLE; index++) {
        if (ThreadLocalSlotType_Free == m_tlsSlotType[index]) {
        m_tlsSlotType[index] = type;
            *pSlotIndex = index;
            break;
        }
    }
    Unlock(m_hTlsLock);

    if (index >= TLS_MINIMUM_AVAILABLE) {
        return E_OUT_OF_MEMORY;
    }
    return NOERROR;
}

ECode CProcess::RelinquishThreadLocalSlot(
    /* [in]  */ Int32 slotIndex,
    /* [out] */ BufferOf<Address> * pUsedPtrs)
{
    CThread * pThread = NULL;
    Int32 i = 0;

    if ((slotIndex <0)
        || (slotIndex >= TLS_MINIMUM_AVAILABLE)
        || (NULL == pUsedPtrs)) {
        return E_INVALID_ARGUMENT;
    }
    Lock(m_hTlsLock);
    if (ThreadLocalSlotType_Free == m_tlsSlotType[slotIndex]) {
        Unlock(m_hTlsLock);
        return E_INVALID_ARGUMENT;
    }

    assert((ThreadLocalSlotType_Value == m_tlsSlotType[slotIndex])
        || (ThreadLocalSlotType_Mem   == m_tlsSlotType[slotIndex])
        || (ThreadLocalSlotType_Obj   == m_tlsSlotType[slotIndex]));

    pUsedPtrs->SetUsed(0);
    i = 0;
    Lock(m_hThreadListLock);
    ForEachDLinkNode(CThread*, pThread, &m_threadList)
    {
        if (ThreadLocalSlotType_Value != m_tlsSlotType[slotIndex]) {
            pUsedPtrs->SetUsed(i + 1);
            pThread->GetLocalSlotValue(slotIndex, (PVoid *)&(*pUsedPtrs)[i]);
            i++;
        }
        pThread->SetLocalSlotValue(slotIndex, NULL);
    }
    Unlock(m_hThreadListLock);
    m_tlsSlotType[slotIndex] = ThreadLocalSlotType_Free;
    Unlock(m_hTlsLock);

    return NOERROR;
}

ECode CProcess::CleanUpThreadLocalSlot(
    /* [in]  */ Int32 slotIndex,
    /* [out] */ BufferOf<Address> * pUsedPtrs)
{
    CThread * pThread = NULL;
    Int32 i = 0;

    if ((slotIndex <0)
        || (slotIndex >= TLS_TOTAL_SLOTS)
        || (NULL == pUsedPtrs)) {
        return E_INVALID_ARGUMENT;
    }
    Lock(m_hTlsLock);
    if (ThreadLocalSlotType_Free == m_tlsSlotType[slotIndex]) {
        Unlock(m_hTlsLock);
        return E_INVALID_ARGUMENT;
    }

    assert((ThreadLocalSlotType_Value == m_tlsSlotType[slotIndex])
        || (ThreadLocalSlotType_Mem   == m_tlsSlotType[slotIndex])
        || (ThreadLocalSlotType_Obj   == m_tlsSlotType[slotIndex]));

    pUsedPtrs->SetUsed(0);
    i = 0;
    Lock(m_hThreadListLock);
    ForEachDLinkNode(CThread*, pThread, &m_threadList)
    {
        if (ThreadLocalSlotType_Value != m_tlsSlotType[slotIndex]) {
            pUsedPtrs->SetUsed(i + 1);
            pThread->GetLocalSlotValue(slotIndex, (PVoid *)&(*pUsedPtrs)[i]);
            i++;
        }
        pThread->SetLocalSlotValue(slotIndex, NULL);
    }
    Unlock(m_hThreadListLock);
    Unlock(m_hTlsLock);

    return NOERROR;
}

ECode CProcess::GetThreadLocalSlotValue(
    /* [in] */ ThreadLocalSlotType type,
    /* [in] */ Int32 slotIndex,
    /* [out] */ PVoid * ppValue)
{
    IThread * pThread = NULL;

    switch (type) {
    case ThreadLocalSlotType_Value:
    case ThreadLocalSlotType_Mem:
    case ThreadLocalSlotType_Obj:
        break;
    default:
        return E_INVALID_ARGUMENT;
    }
    if ((slotIndex < 0)
     || (slotIndex >= TLS_TOTAL_SLOTS)
     || (NULL == ppValue)) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hTlsLock);
    if (type != m_tlsSlotType[slotIndex]) {
        Unlock(m_hTlsLock);
        return E_INVALID_ARGUMENT;
    }
    Unlock(m_hTlsLock);

    CPseudoKernel::Thread_GetCurrent(&pThread);
    //BUGBUG: NULL in dllmain process detach
	if (pThread == NULL) {
        *ppValue = NULL;
        return E_FAIL;
	}
    ((CThread *)pThread)->GetLocalSlotValue(slotIndex, ppValue);
    pThread->Release();

    return NOERROR;
}

ECode CProcess::SetThreadLocalSlotValue(
    /* [in]  */ ThreadLocalSlotType type,
    /* [in]  */ Int32 slotIndex,
    /* [in]  */ PVoid pValue)
{
    IThread * pThread = NULL;

    switch (type) {
    case ThreadLocalSlotType_Value:
    case ThreadLocalSlotType_Mem:
    case ThreadLocalSlotType_Obj:
        break;
    default:
        return E_INVALID_ARGUMENT;
    }
    if ((slotIndex < 0)
      || (slotIndex >= TLS_TOTAL_SLOTS)) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hTlsLock);
    if (type != m_tlsSlotType[slotIndex]) {
        Unlock(m_hTlsLock);
        return E_INVALID_ARGUMENT;
    }
    Unlock(m_hTlsLock);

    CPseudoKernel::Thread_GetCurrent(&pThread);
    ((CThread *)pThread)->SetLocalSlotValue(slotIndex, pValue);
    pThread->Release();

    return NOERROR;
}

void CProcess::AttachThread(
        /* [in] */ CThread * pThread)
{
    LOCK_THREAD_LIST;
    m_threadList.InsertLast(pThread);
    m_threadListState++;
    UNLOCK_THREAD_LIST;
}

void CProcess::DetachThread(
        /* [in] */ CThread * pThread)
{
    LOCK_THREAD_LIST;
    pThread->Detach();
    m_threadListState++;
    UNLOCK_THREAD_LIST;
}

void CProcess::DetachModule(CModule * pModule)
{
    LOCK_MODULE_LIST;
    pModule->Detach();
    m_moduleListState++;
    UNLOCK_MODULE_LIST;
}

void CProcess::DoAtExit(
        /* [in] */ ExitCode exitCode)
{
    IThread * pCurrent = NULL;
    CThread * pThread = NULL;

    m_exitCode = exitCode;

    Lock(m_hThreadListLock);
    CPseudoKernel::Thread_GetCurrent(&pCurrent);
    if (!::IsMainThread(pCurrent)) {
        ((CThread *)pCurrent)->Detach();
        ((CThread *)pCurrent)->DoAtQuit(exitCode, FALSE);
        pCurrent->Release();
    }
    else {
        pCurrent->Release();
        pCurrent = NULL;
    }

    ((CThread *)m_pMainThread)->Detach();
    ((CThread *)m_pMainThread)->DoAtQuit(exitCode, FALSE);

    while (!m_threadList.IsEmpty()) {
        pThread = (CThread *)m_threadList.Next();
        pThread->Detach();
        pThread->DoAtQuit(exitCode, TRUE);
        pThread->Release();
        pThread = NULL;
    }

    Millisecond32 time[2] = { 0 };
    AuraProcess_GetProcessorTimes(m_hProcess,
                             (Aura_Millisecond32 *)&time[0],
                             (Aura_Millisecond32 *)&time[1]);
    CPseudoCentral::Process_TransferInfo(m_processId,
                                        m_exitCode,
                                        time[0], time[1]);
    Unlock(m_hThreadListLock);
    CServiceKit::S_DeleteAllKits();
    _Elastos_SequencedContext_Leave();
    AuraProcess_Exit(exitCode);

    assert(0);
    return;
}

ECode CProcess::LoadModule(
    /* [in]  */ WString name,
    /* [in]  */ ModuleLoadFlags flags,
    /* [out] */ IModule ** ppModule)
{
    CModule * pModule = NULL;
    ECode ec = NOERROR;

    assert(!name.IsNullOrEmpty());
    assert(NULL != ppModule);

    LOCK_MODULE_LIST;
    ForEachDLinkNode(CModule*, pModule, &m_moduleList)
    {
        if (pModule->Compare(name)) {
            *ppModule = static_cast<IModule*>(pModule);
            (*ppModule)->AddRef();
            UNLOCK_MODULE_LIST;
            return NOERROR;
        }
    }

    pModule = new CModule(m_processId, (IProcess *)this, m_hModuleListLock);
    if (NULL == pModule) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pModule->Initialize(name, flags);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    pModule->AddRef();
    m_moduleList.InsertLast(pModule);
    m_moduleListState++;
    UNLOCK_MODULE_LIST;

    *ppModule = static_cast<IModule *>(pModule);

    return ec;

ErrorExit:
    UNLOCK_MODULE_LIST;
    if (NULL != pModule) {
        delete pModule;
    }
    return ec;
}

ECode CProcess::SetTraceArgs(
    /* [in]*/ Int32 argId,
    /* [in]*/ Int32 index,
    /* [in]*/ Address watchAddress)
{
    return E_NOT_IMPLEMENTED;
}

ECode CProcess::SetTraceDebug(
    /* [in] */ Boolean debug)
{
    return E_NOT_IMPLEMENTED;
}

ECode CProcess::IsTraceDebug(
    /* [out] */ Boolean *pDebug)
{
    return E_NOT_IMPLEMENTED;
}

#define ALL_SYSTEM_EVENTS                 \
        (SystemEvent_Break                \
        | SystemEvent_SessionEnd          \
        | SystemEvent_TimeChanged         \
        | SystemEvent_LowMemory           \
        | SystemEvent_CriticallyLowMemory \
        | SystemEvent_Shutdown)

ECode CProcess::RequestSystemEvent(
    /* [in] */ SystemEvents intrestedEvents,
    /* [out] */ IEvent ** ppEvent)
{
    Boolean bManualReset = FALSE;
    CSystemEvent *tempEvent;

    if (NULL == ppEvent
      || !intrestedEvents
      || ALL_SYSTEM_EVENTS != (intrestedEvents | ALL_SYSTEM_EVENTS)) {
        return E_INVALID_ARGUMENT;
    }

    if (intrestedEvents & SystemEvent_LowMemory) {
        if (intrestedEvents != SystemEvent_LowMemory) {
            // Manual reset event conflict with other system events
            return E_INVALID_ARGUMENT;
        }
        bManualReset = TRUE;
    }

    if (intrestedEvents & SystemEvent_CriticallyLowMemory) {
        if (intrestedEvents != SystemEvent_CriticallyLowMemory) {
            // Manual reset event conflict with other system events
            return E_INVALID_ARGUMENT;
        }
        bManualReset = TRUE;
    }

    tempEvent = CreateSystemEvent(this, bManualReset);
    if (NULL == tempEvent) {
        return E_OUT_OF_MEMORY;
    }
    *ppEvent = tempEvent;
    return NOERROR;
}

ECode CProcess::S_Create(
    /* [out] */ IProcess ** ppProcess,
    /* [out] */ IThread  ** ppMainThread)
{
    CProcess * pProcess = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppProcess);
    assert(NULL != ppMainThread);

    pProcess = new CProcess();
    if (NULL == pProcess) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pProcess->Initialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    *ppProcess = static_cast<IProcess *>(pProcess);
    (*ppProcess)->AddRef();

    *ppMainThread = pProcess->m_pMainThread;
    (*ppMainThread)->AddRef();

    return NOERROR;

ErrorExit:
    if (NULL != pProcess) {
        delete pProcess;
        pProcess = NULL;
    }
    return ec;
}

